﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace FerrSimplicity
{
    /// <summary>
    /// This component manages physical forces, like velocity and acceleration.
    /// </summary>
    public class ComForce : BaseComponent
    {
        #region Properties
        /// <summary>
        /// The velocity of the object, in units per second
        /// </summary>
        public Vector3 Velocity            { get; set; }
        /// <summary>
        /// The constant acceleration applied to the velocity, in units per second
        /// </summary>
        public Vector3 Acceleration        { get; set; }
        /// <summary>
        /// The speed at which the object rotates about each axis, in radians per second
        /// </summary>
        public Vector3 AngularVelocity     { get; set; }
        /// <summary>
        /// The acceleration applied to the angular velocity, in radians per second
        /// </summary>
        public Vector3 AngularAcceleration { get; set; }

        /// <summary>
        /// If you wish to add force to the object for a single frame, put it here.
        /// It will get zeroed out next Update when applied with all other forces.
        /// </summary>
        public Vector3 Force        { get; set; }
        /// <summary>
        /// If you wish to add angular force to the object for a single frame, put it here.
        /// It will get zeroed out next Update when applied with all other angular forces.
        /// </summary>
        public Vector3 AngularForce { get; set; }
        /// <summary>
        /// Friction is applied as part of acceleration, (-Velocity * Friction)
        /// </summary>
        public float   Friction     { get; set; }

        /// <summary>
        /// This gravity is applied to all ComForce components, in units per second.
        /// It defaults to zero.
        /// </summary>
        public static Vector3 Gravity { get; set; }
        #endregion

        #region Constructor
        /// <summary>
        /// A default parameterless constructor for use with cloning
        /// </summary>
        public ComForce()
            : this(Vector3.Zero, 0) { }
        /// <summary>
        /// A basic constructor, copies values into local public fields
        /// </summary>
        /// <param name="aVelocity">Initial velocity for the component, units per second</param>
        public  ComForce(Vector3 aVelocity)
            : this(aVelocity, 0.0f) { }
        /// <summary>
        /// A basic constructor, copies values into local public fields
        /// </summary>
        /// <param name="aVelocity">Initial velocity for the component, units per second</param>
        /// <param name="aFriction">Friction is applied as part of acceleration, (-Velocity * Friction)</param>
        public ComForce(Vector3 aVelocity, float aFriction)
        {
            Friction = aFriction;
            Velocity = aVelocity;
        }
        #endregion

        #region Overrides
        public override void Update(GameTime aGameTime)
        {
            // get time variables, store them for ease of use
            float time = (float)aGameTime.ElapsedGameTime.TotalSeconds;
            float timeSq = time * time;

            // apply forces to velocity
            Vector3 totalForce = Acceleration + Force + Gravity + (-Velocity * Friction);
            Velocity                  += totalForce * timeSq;
            Parent.Transform.Position += Velocity   * time;

            Force = Vector3.Zero;

            // apply forces to angular velocity
            totalForce = AngularAcceleration + AngularForce + (-AngularVelocity * Friction);
            AngularVelocity           += totalForce      * timeSq;
            Parent.Transform.Rotation += AngularVelocity * time;

            AngularForce = Vector3.Zero;

            base.Update(aGameTime);
        }
        #endregion
    }
}
